/**
 * @author Kristian Mandrup
 * @date June 10, 2009
 * @version 0.1
 * 
 * m3gen :: JsTreeModelGenerator
 * 
 * - Builds a jsTree model used to draw a tree by jsTree widget
 * 
 * Usage 
 * -----
 * 
 * // Initialize a JsTreeModelGenerator instance with a generator model (rules for generation process)
 * var my_jsTreeModelGenerator = new JsTreeModelGenerator(generatorModel);
 * 
 * // get an instance model
 * var my_instanceModel = [...]; // JSON model
 * 
 * // execute the JsTreeModelGenerator with the instance model
 * var jsTreeModel = my_jsTreeModelGenerator.execute(my_instanceModel);
 */

/**
 * JsTreeModelGenerator constructor
 * Sets up JsTreeModelGenerator for use
 * 
 * FLOW:
 * - calls init
 * 
 * @param {Object} modelsObj
 * 
 * modelsObj:
 * - generatorModel
 * - jsonInstanceModel
 * - constructors
 *   - exceptionHandler
 *   - jsonObjParser
 *   - jsTreeNodeBuilder
 * 
 * or modelsObj can simply be the generatorModel
 */
m3gen.JsTreeModelGenerator = function(modelsObj) {
	if (arguments.length < 1 || m3gen.util.invalidOptions(modelsObj))
		return;
	this.init(modelsObj);
}

// inherit from Base and Parser
m3gen.JsTreeModelGenerator.inherits(m3gen.Base);	
// m3gen.JsTreeModelGenerator.inherits(m3gen.Parser);	

/**
 * Initialize JsTreeModelGenerator for use
 * 
 * FLOW:
 * - call Base.init
 * - set global exec state (used by all m3gen components)
 * - always: 	 set generator model to use for parsing/generation
 * 		- this also sets: nodeList (nodes to show as open/closed)
 * 		- ...
 * - optionally: set instance model to parse
 * - set visited list (ids encountered)
 *  
 * @param {Object} modelsObj
 */
m3gen.JsTreeModelGenerator.prototype.init = function(modelsObj){
	this.setClassName('JsTreeModelGenerator');
			
	var constructors = modelsObj.constructors || {};	
	this.uber('init', constructors);		
	this.initializeGenerator(modelsObj)
}

/**
 * doExecute default empty wrapper
 * @param {Object} options
 */
m3gen.JsTreeModelGenerator.prototype.execute = function(options){
	return this.doExecute(options);
}

/**
 * JsTreeModelGenerator execute
 * 
 * If the instance model has been set using the constructor, execute can be called with no arguments.			
 * Normally however, JsTreeModelGenerator is called with an instance model and optionally a nodeStateList, 
 * containing the lists of branch nodes to show in "open" and "closed" state.
 * nodeStateList {open: [...], closed: [..]}.
 * 
 * FLOW:
 * - set using options
 * - create initial empty jsTreeResultModel to be filled
 * - iterate each jsonObj inside jsonInstanceModel array  
 * - TRY: create a nodeObj for each Json object encountered
 * 	- create jsTreeNode from nodeObj
 * 	- add jsTreeNode to result list
 * - return jsTreeNode result list  
 * 
 * 
 * @param {Object} options
 * 
 * options:
 * - jsonInstanceModel
 * OR
 * - modelsObj
 *   - jsonInstanceModel
 *   - generatorModel (optional)
 *   - executeOptions (optional)
 *  
 * events: GenerateTreeInstanceModel.execute, NodeObjNotCreated
 * 
 * TODO: enable MainExceptionHandler ?
 */

m3gen.JsTreeModelGenerator.prototype.doExecute = function (options) {	
	var that = this.getTheContext(this);
	// try {
		var jsonInstanceModel = that.getInitialInstanceModel(options);

		// set global execution options
		this.setLanguageModeOn(this.getObjDef(options.languagesOn, false));
		this.setEmptyBranchesModeOn(this.getObjDef(options.includeEmptyBranchesOn, false))
		// create initial empty jsTreeResultModel to be filled
		var jsTreeResultModel = [];
		// iterate each jsonObj inside jsonInstanceModel array 
		var index = 0;		

		jsonInstanceModel.forEach(function(jsonObj) {
			// create a nodeObj for each Json object encountered
			var nodeObj = that.createNodeObj(jsonObj);						
			if (nodeObj) {
				// create jsTreeNode from nodeObj
				var jsTreeNode 	= that.createJsTreeNodeObj(nodeObj);
				
				// add jsTreeNode node to result list
				that.addJsTreeNodeToModel(jsTreeResultModel, jsTreeNode); 
			} else {
				console.log('JsTreeModelGenerator:execute Invalid node obj');
				that.handle(m3gen.msg.NodeObjNotCreated);
			}
			index++;
		});		
		return jsTreeResultModel;			 
	/*
	} catch (e) {	
	  	// any and all errors will go to this handler
		that.callExceptionHandler(e);
  	} 
  	*/
}
	
/**
 * creates a NodeObj useful for creating a jsTreeNode object
 * 
 * FLOW:
 * - set activeObj
 * - create instance of JsonObjParser
 * - execute JsonObjParser to create a nodeObj
 * - return the nodeObj generated
 * 
 * @param 	{JSON obj} 	jsonObj
 * @return 	{NodeObj} 	nodeObj - the nodeObj
 * 
 * events: CreateNodeObj
 */

m3gen.JsTreeModelGenerator.prototype.createNodeObj = function(jsonObj) {					
	// set activeObj
	var activeObj = this.setActiveObj(jsonObj);		
	// execute JsonObjParser to create a nodeObj
	return this.getJsonObjParserInstance().execute(activeObj);
}

/**
 * creates a JsTreeNode from a NodeObj
 * 
 * FLOW:
 * - create instance of JsTreeNodeBuilder
 * - execute jsTreeNodeBuilder with a nodeObj to create a jsTreeNode
 * - return the jsTree node
 * 
 * @param {Object} nodeObj	- the nodeObj to use for creating the jsTree node 
 */
m3gen.JsTreeModelGenerator.prototype.createJsTreeNodeObj = function(nodeObj) {	
	// execute jsTreeNodeBuilder with the nodeObj to create a jsTree node from it
	var jsTreeNode = this.getJsTreeNodeBuilderInstance().execute(nodeObj);		
	// return the jsTree node	
	return jsTreeNode;
}

	
/**
 * Add JsTreeNode to final jsTreeNode model
 * @param {Object} jsTreeResultModel
 * @param {Object} jsTreeNode
 */
m3gen.JsTreeModelGenerator.prototype.addJsTreeNodeToModel = function(jsTreeResultModel, jsTreeNode) {
	jsTreeResultModel.push(jsTreeNode);
}